import {pathJoin} from "./PathUtils";
import LimitPromise from "../utils/LimitPromise";
import {httpUtils} from "./HttpUtils";
import {babelTransformCode} from "./BabelGenUtils";

export function getScopedId(url: string) {
  return 'zhixin-path-' + url.replace(/(\/)|(\.)/g, () => {
    return '-'
  }).toLowerCase()
}

export const IsLoaderVue = {}

/**
 * 提供给浏览器查找文件url
 * @param scopedId
 */
export function scopedId2FilePath(scopedId: string) {
  if (!scopedId.startsWith('zhixin-path-')) {
    console.error(window.__chineseTranscode__('scopedId一定是zhixin-path-开头'))
    return
  }
  const url = Object.keys(IsLoaderVue)
    .find(i => scopedId === getScopedId(i))
  console.log(window.__chineseTranscode__('文件地址：') + url)
}

export interface TransLateItem {
  /**
   * 文件的类型
   */
  fileType: string;
  /**
   * 在环境中可以被调用到的方法，这里写调用路径，
   * 比如：BrowseVueLoader.urlFileToVue
   * 这个方法返回一个函数，
   * 函数里面返回一个promise<any>，相当于这个方法调用了func
   * 这个方法的this中会有一个__zhiXinFileId指向当前文件的路径
   */
  asyncFunc?: string;
  /**
   * 在环境中可以被调用到的方法，这里写调用路径，这个方法返回Promise<any>，
   * 方法的参数一定只有一个且为文件的url
   * 这个方法的this中会有一个__zhiXinFileId指向当前文件的路径
   */
  func?: string;

  /**
   * 在环境中可以被调用到的方法，这里写调用路径
   * 判断优先判断是否存在loader，存在就用loader就行了
   * loader接受两个参数(url,code)=> Promise<any>
   */
  loader?: string;
  /**
   * 在环境中可以被调用到的对象，这里写调用路径
   * 处理完成的文件缓存的对象
   */
  saveLoader?: string;
}

let translateList: TransLateItem[] = [
  {
    fileType: '.vue',
    asyncFunc: 'BrowseVueLoader.urlFileToVueAsync',
    func: 'BrowseVueLoader.urlFileToVue',
  },
  {
    fileType: '.js',
    asyncFunc: 'BrowseVueLoader.urlFileToJsAsync',
    func: 'BrowseVueLoader.urlFileToJs',
  },
  {
    fileType: '.json',
    asyncFunc: 'BrowseVueLoader.urlFileToJsonAsync',
    func: 'BrowseVueLoader.urlFileToJson',
  },
]

/**
 * 使用这个替换，最后在eval的时候第一个参数一定是__zhixinVCom
 * () => import("","")
 * 里面有一个变量__zhiXinFileId就是当前文件的地址
 * @param text
 */
export function replaceImport(text: string) {
  // () => import("")
  return text.replace(/\(\) => import\("(.*?)"\)/g, ($0, $1: string) => {
    let find = translateList.find(i => $1.endsWith(i.fileType))
    if (find) {
      if (find.loader) {
        return `BrowseVueLoader.urlFileToCommonAsync.call(__zhixinVCom,"${$1}",${find.saveLoader || 'null'},${find.loader})`
      }
      if (find.asyncFunc) {
        return `${find.asyncFunc}.call(__zhixinVCom,"${$1}")`
      }
    }
    console.warn(`${window.__chineseTranscode__('无法处理当前文件')}${$1}${window.__chineseTranscode__('，请添加处理文件的loader')}`)
    return ''
  })
}

export let loaderCallBack = (finish: boolean, url: string) => {

}

export function setLoaderCallBack(call) {
  if (call) {
    loaderCallBack = call
  }
}

//<img
//         :src='require("./../img/scblue.png")'
//         alt="这是测试">
export function replaceRequire(code: string, url: string): string {
  return code.replace(/require\("(.*)"\)/g, ($0, $1) => {
    return `"${pathJoin(url, $1)}"`
  })
}

/**
 * 替换日志
 * @param code
 * @param url
 */
export function replaceLogWithPlugin(code: string, url: string): string {
  code = code.replace(/logWithPlugin\.getFileName\(\)/g, ($0, $1) => {
    return `"${url}"`
  })
  code = code.split('\n').map((row, index) => {
    return row.replace(/logWithPlugin\.getCurrentLine\(\)/g, (index + 1) + '')
  }).join('\n')
  return code
}

export function exportDefaultUtils(url: string, jsCode: string): Promise<any> {
  let self = {
    __zhiXinFileId: url, // __zhixinVCom
  }
  return new Promise<any>(resolve => {
    // 支持 import Com from "路径";
    let imports: { name: string, path: string }[] = []
    jsCode = jsCode.replace(/import (.*?) from "(.*?)";/g, ($0, $1, $2) => {
      imports.push({
        name: $1,
        path: $2,
      })
      return ''
    })
    jsCode = jsCode.replace('export default', 'resolve(')
    jsCode = jsCode + ')'
    let loadFile = imports.map(i => {
      let find = translateList.find(t => i.path.endsWith(t.fileType))
      if (find) {
        if (find.loader) {
          return `BrowseVueLoader.urlFileToCommon.call(__zhixinVCom,"${i.path}",${find.saveLoader || 'null'},${find.loader})`
        }
        if (find.func) {
          return `${find.func}.call(__zhixinVCom,"${i.path}")`
        }
      }
      console.warn(`${window.__chineseTranscode__('无法处理当前文件')}${i.path}${window.__chineseTranscode__('，请添加处理文件的loader')}`)
      return ''
    }).join(',')
    let resCom = imports.map((i, index) => {
      return `let ${i.name}=__ZhiXinResCom[${index}]`
    }).join(';')
    let fun = `const __zhixinGenCodeToObjPromise = new Promise((resolve) => {
    try {
      Promise.all([${loadFile}]).then(function (__ZhiXinResCom) {
          ${resCom}
          ${jsCode}
        })
    } catch (e) {
      console.error('${window.__chineseTranscode__('错误文件')}：${url}', e)
      resolve({})
    }
  })`
    try {
      fun = babelTransformCode(fun,url)
      fun+='\n return __zhixinGenCodeToObjPromise'
      fun+=`\n //# sourceURL=${url}` // 添加sourceURL，让全局window.onerror的filename有值
      // 若无需new Function的动态参数特性，可用eval替代
      let func =eval(`(function(__zhixinVCom) { ${fun}\n })`);
      func(self)
        .then(res => {
          resolve(res)
        })
        .catch(e => {
          console.error(e)
          resolve(self)
        })
    } catch (e) {
      console.warn(window.__chineseTranscode__('代码编译出错：------------------------------------------------'))
      console.warn(fun)
      console.warn(`${window.__chineseTranscode__('错误文件')}：${url}`)
      console.warn(window.__chineseTranscode__('代码编译出错：------------------------------------------------'))
      console.error(e)
      resolve(self)
    }
  })
}

const urlLimit: { [key: string]: LimitPromise<any> } = {}

const IsLoaderJs = {}

const saveLoaderOther = {}

export type LoaderFunc = (url: string, code: string) => Promise<any>

export function getBaseUrl(baseUrl: string): string {
  if (!baseUrl && location && location.pathname) {
    // 使用web绝对路径，这样就可以读取到web目录下面任何位置的文件
    baseUrl = location.pathname
  }
  return baseUrl
}

export function urlFileToCommon(url: string, saveLoader, loaderFunc: LoaderFunc) {
  // @ts-ignore
  let baseUrl = getBaseUrl(this.__zhiXinFileId as string)
  if (baseUrl) {
    url = pathJoin(baseUrl, url)
  }
  if (!urlLimit[url]) {
    urlLimit[url] = new LimitPromise<any>(1)
  }
  return urlLimit[url].call(() => {
    return new Promise(resolve => {
      if (!saveLoader) {
        saveLoader = saveLoaderOther
      }
      if (saveLoader[url]) {
        resolve(saveLoader[url])
      } else {
        httpUtils(url).then(code => {
          code = replaceImport(code)
          code = replaceRequire(code, url)
          code = replaceLogWithPlugin(code, url)
          return loaderFunc(url, code)
        }).then(js => {
          saveLoader[url] = js
          resolve(js)
        }).catch(err => {
          console.error(err)
          resolve({})
        })
      }
    })
  })
}

export function urlFileToCommonAsync(url: string, saveLoader, loaderFunc: LoaderFunc) {
  return () => {
    return urlFileToCommon.call(this, url, saveLoader, loaderFunc)
  }
}

export function urlFileToJs(url: string) {
  return urlFileToCommon.call(this, url, IsLoaderJs, exportDefaultUtils)
}

export function urlFileToJsAsync(url: string) {
  return () => {
    return urlFileToJs.call(this, url)
  }
}

const saveJsonLoader = {}

export function urlFileToJson(url) {
  return urlFileToCommon.call(this, url, saveJsonLoader, (url, code) => {
    return Promise.resolve(JSON.parse(code))
  })
}

export function urlFileToJsonAsync(url) {
  return () => {
    return urlFileToJson.call(this, url)
  }
}

/**
 * 添加代码转换
 * @param item
 */
export function addTranslate(item: TransLateItem) {
  translateList.push(item)
}

















